﻿using Core.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Core.Authorization
{
    public abstract class Authorized<TUser>
    {
        public static int InitialUsersNumber = 999;
        public static int InitialRolesNumber = 99;

        private static readonly int[] EmptyIntArray = new int[0];

        private TUser[] Users;
        private int[][] Roles;
        private int[][] Commands;

        private object Lock;

        public Authorized()
        {
            Users = new TUser[InitialUsersNumber];
            Roles = new int[InitialUsersNumber][];
            Commands = new int[InitialUsersNumber][];

            Lock = new object();
        }

        protected abstract int[] GetRoles(int UserId);

        protected abstract int[] GetCommands(int RoleId);

        private int[] InternalGetCommands(int RoleId)
        {
            var Commands = GetCommands(RoleId);

            if (Commands == null || Commands.Length == 0)
            {
                return EmptyIntArray;
            }

            var CommandsMap = new int[Commands.Max() / 32 + 1];

            foreach (var Item in Commands)
            {
                CommandsMap[(Item / 32)] |= (1 << (Item % 32));
            }

            return CommandsMap;
        }

        public void Authorize(int UserId, TUser UserInfo)
        {
            if (IsAuthorized(UserId))
            {
                throw new Exception(UserId + " -- 已登录。");
            }

            lock (Lock)
            {
                if (Users.Length <= UserId)
                {
                    Array.Resize(ref Users, ArrayHelper.GetPrime(UserId));
                }

                Users[UserId] = UserInfo;

                ReAuthorize(UserId);
            }
        }

        public void ReAuthorize(int UserId)
        {
            lock (Lock)
            {
                Roles[UserId] = GetRoles(UserId);

                if (Roles[UserId] == null)
                {
                    Roles[UserId] = EmptyIntArray;
                }

                foreach (var Item in Roles[UserId])
                {
                    if (Commands.Length <= Item || Commands[Item] == null)
                    {
                        RefreshRole(Item);
                    }
                }
            }
        }

        public void RefreshRole(int RoleId)
        {
            lock (Lock)
            {
                if (Commands.Length <= RoleId)
                {
                    Array.Resize(ref Commands, ArrayHelper.GetPrime(RoleId));
                }

                Commands[RoleId] = InternalGetCommands(RoleId);
            }
        }

        public void DeAuthorize(int UserId)
        {
            if (!IsAuthorized(UserId))
            {
                throw new Exception(UserId + " -- 未登录。");
            }

            lock (Lock)
            {
                Users[UserId] = default(TUser);
                Roles[UserId] = null;
            }
        }

        public bool IsAuthorized(int UserId)
        {
            return UserId >= 0 && UserId < Roles.Length && Roles[UserId] != null;
        }

        public bool IsAuthorized(int UserId, int CommandId)
        {
            if (!IsAuthorized(UserId))
            {
                return false;
            }

            if (CommandId < 0)
            {
                return false;
            }

            int MinLength = CommandId / 32 + 1;

            int High = CommandId / 32;
            int Low = CommandId % 32;

            foreach (var Item in Roles[UserId])
            {
                if (Commands[Item].Length >= MinLength && (Commands[Item][High] & (1 << Low)) != 0)
                {
                    return true;
                }
            }

            return false;
        }
        
        public TUser this[int UserId]
        {
            get
            {
                if (UserId >= 0 && UserId < Roles.Length)
                {
                    return Users[UserId];
                }

                throw new Exception(UserId + " -- 未登录。");
            }
        }
    }
}
